﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Activation;
using System.IO;
using SilverlightDatabase.Compression;
using System.Configuration;

namespace SilverlightDatabase.Server
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class SilverlightDatabaseServer : ISilverlightDatabaseServer
    {
        #region ISilverlightDatabaseServer Members
        public bool PutDatabase(SilverlightDatabaseData data)
        {
            bool returnValue = false;

            if (data != null)
            {
                Database database = ConvertToDatabase(data);
                returnValue = GetProcessor().PutDatabase(database);
            }

            return returnValue;
        }

        public SilverlightDatabaseData GetDatabase(string databaseName, string password, bool useCompression)
        {
            Database database = GetProcessor().GetDatabase(databaseName, password, useCompression);
            return GetSilverlightDatabaseData(database);
        }

        public SilverlightDatabaseData UpdateDatabase(SilverlightDatabaseData data)
        {
            Database database = ConvertToDatabase(data);
            database = GetProcessor().UpdateDatabase(database);
            return GetSilverlightDatabaseData(database);
        }

        #endregion

        private Database ConvertToDatabase(SilverlightDatabaseData data)
        {
            Database database = null;
            if (data.ClientDatabaseData != null)
            {
                string[] parts;
                Type tableType = null;
                byte[] databaseDefinition = data.ClientDatabaseData[data.DatabaseName];
                using (MemoryStream stream = new MemoryStream(databaseDefinition))
                {
                    StreamReader reader = new StreamReader(stream);
                    string content;
                    if (data.UseCompression)
                    {
                        content = CompressionUtility.DecompressToString(CompressionUtility.ReadFullStream(stream));
                    }
                    else
                    {
                        content = reader.ReadToEnd();
                    }
                    if (!string.IsNullOrEmpty(data.Password))
                    {
                        content = Cryptography.Decrypt(content, data.Password);
                    }
                    parts = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                    reader.Close();
                    stream.Close();
                    database = Database.CreateDatabase(data.DatabaseName, data.Password, data.UseCompression, true);
                }

                if (parts != null)
                {
                    for (int counter = 1; counter < parts.Length; counter++)
                    {
                        string content = string.Empty; ;
                        string rowTypeString = parts[counter];
                        Type rowType = Type.GetType(rowTypeString);
                        tableType = typeof(Table<>).MakeGenericType(new Type[] { rowType });

                        byte[] tableDefinition = data.ClientDatabaseData[rowTypeString.Substring(0, rowTypeString.IndexOf(",")).Trim()];
                        using (MemoryStream stream = new MemoryStream(tableDefinition))
                        {
                            StreamReader reader = new StreamReader(stream);
                            if (data.UseCompression)
                            {
                                content = CompressionUtility.DecompressToString(CompressionUtility.ReadFullStream(stream));
                            }
                            else
                            {
                                content = reader.ReadToEnd();
                            }
                            if (!string.IsNullOrEmpty(data.Password))
                            {
                                content = Cryptography.Decrypt(content, data.Password);
                            }

                            reader.Close();
                            stream.Close();
                        }


                        database.LoadTable(content, tableType);

                    }
                }
            }
            return database;
        }


        private IDatabaseProcessor GetProcessor()
        {
            string typeDefinition = ConfigurationManager.AppSettings["IDatabaseProcessor"];
            Type type = Type.GetType(typeDefinition);
            return Activator.CreateInstance(type) as IDatabaseProcessor;
        }

        private SilverlightDatabaseData GetSilverlightDatabaseData(Database database)
        {
            SilverlightDatabaseData data = new SilverlightDatabaseData();
            Dictionary<string, byte[]> clientData = new Dictionary<string, byte[]>();
            using (MemoryStream stream = new MemoryStream())
            {
                database.WriteDatabaseToStream(stream);
                clientData.Add(database.DatabaseName, stream.ToArray());
            }
            foreach (var table in database.Tables)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    table.WriteDTableToStream(stream);
                    clientData.Add(table.RowType.FullName, stream.ToArray());
                }
            }
            data.DatabaseName = database.DatabaseName;
            data.Password = database.Password;
            data.UseCompression = database.UseCompression;
            data.ClientDatabaseData = clientData;
            return data;
        }
    }
}
